home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ian & Stuart's Australian Mac: Not for Sale
/
Another.not.for.sale (Australia).iso
/
hold me in your arms
/
PGP 2.6
/
pgp2.6 Source
/
src
/
randpool.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-05-18
|
6KB
|
190 lines
/*
* True random number computation and storage
*
* (c) Copyright 1990-1994 by Philip Zimmermann. All rights reserved.
* The author assumes no liability for damages resulting from the use
* of this software, even if the damage results from defects in this
* software. No warranty is expressed or implied.
*
* Note that while most PGP source modules bear Philip Zimmermann's
* copyright notice, many of them have been revised or entirely written
* by contributors who frequently failed to put their names in their
* code. Code that has been incorporated into PGP from other authors
* was either originally published in the public domain or is used with
* permission from the various authors.
*
* PGP is available for free to the public under certain restrictions.
* See the PGP User's Guide (included in the release package) for
* important information about licensing, patent restrictions on
* certain algorithms, trademarks, copyrights, and export controls.
*
* Written by Colin Plumb.
*/
#include <stdlib.h>
#include <string.h>
#include "randpool.h"
#include "usuals.h"
#include "md5.h"
/* The pool must be a multiple of the 16-byte (128-bit) MD5 block size */
#define RANDPOOLWORDS ((RANDPOOLBITS+127 & ~127) >> 5)
#if RANDPOOLWORDS <= 16
#error Random pool too small - please increase RANDPOOLBITS in randpool.h
#endif
/* Must be word-aligned, so make it words. Cast to bytes as needed. */
static word32 randPool[RANDPOOLWORDS]; /* Random pool */
static unsigned randPoolGetPos = sizeof(randPool); /* Position to get from */
static unsigned randPoolAddPos = 0; /* Position to add to */
static void
xorbytes(byte *dest, byte const *src, unsigned len)
{
while (len--)
*dest++ = *src++;
}
/*
* Destroys already-used random numbers. Ensures no sensitive data
* remains in memory that can be recovered later. This is also
* called to "stir in" newly acquired environmental noise bits before
* removing any random bytes.
*
* The transformation is carried out by "encrypting" the data in CFB
* mode with MD5 as the block cipher. Then, to make certain the stirring
* operation is strictly one-way, we destroy the key, getting 64 bytes
* from the beginning of the pool and using them to reinitialize the
* key. These bytes are not returned by randPoolGetBytes().
*
* The stirring operation is done twice, to ensure that each bit in the
* pool depends on each bit of entropy XORed in after each call to
* randPoolStir().
*
* To make this useful for pseudo-random (that is, repeatable) operations,
* the MD5 transformation is always done with a consistent byte order.
* MD5Transform itself works with 32-bit words, not bytes, so the pool,
* usually an array of bytes, is transformed into an array of 32-bit words,
* taking each group of 4 bytes in big-endian order. At the end of the
* stirring, the transformation is reversed.
*/
void
randPoolStir(void)
{
int i;
byte *p;
word32 t;
word32 iv[4];
static word32 randPoolKey[16] = {0};
/* Convert to word32s for stirring operation */
p = (byte *)randPool;
for (i = 0; i < RANDPOOLWORDS; i++) {
t = (word32)((unsigned)p[3]<<8 | p[2]) << 16 |
(unsigned)p[1]<<8 | p[0];
randPool[i] = t;
p += 4;
}
/* Start IV from last block of randPool */
memcpy(iv, randPool+RANDPOOLWORDS-4, sizeof(iv));
/* First CFB pass */
for (i = 0; i < RANDPOOLWORDS; i += 4) {
MD5Transform(iv, randPoolKey);
iv[0] = randPool[i ] ^= iv[0];
iv[1] = randPool[i+1] ^= iv[1];
iv[2] = randPool[i+2] ^= iv[2];
iv[3] = randPool[i+3] ^= iv[3];
}
/* Get new key */
memcpy(randPoolKey, randPool, sizeof(randPoolKey));
/* Second CFB pass */
for (i = 0; i < RANDPOOLWORDS; i += 4) {
MD5Transform(iv, randPoolKey);
iv[0] = randPool[i ] ^= iv[0];
iv[1] = randPool[i+1] ^= iv[1];
iv[2] = randPool[i+2] ^= iv[2];
iv[3] = randPool[i+3] ^= iv[3];
}
/* Get new key */
memcpy(randPoolKey, randPool, sizeof(randPoolKey));
/* Wipe iv from memory */
memset(iv, 0, sizeof(iv));
/* Convert randPool back to bytes for further use */
p = (byte *)randPool;
for (i = 0; i < RANDPOOLWORDS; i++) {
t = randPool[i];
p[0] = t>>24;
p[1] = t>>16;
p[2] = t>>8;
p[3] = t;
p += 4;
}
/* Set up pointers for future addition or removal of random bytes */
randPoolAddPos = 0;
randPoolGetPos = sizeof(randPoolKey);
}
/*
* Make a deposit of information (entropy) into the pool. The bits
* deposited need not have any particular distribution; the stirring
* operation transformes them to uniformly-distributed bits.
*/
void
randPoolAddBytes(byte const *buf, unsigned len)
{
unsigned t;
while (len > (t = sizeof(randPool) - randPoolAddPos)) {
xorbytes((byte *)randPool+randPoolAddPos, buf, t);
buf += t;
len -= t;
randPoolStir();
}
if (len) {
xorbytes((byte *)randPool+randPoolAddPos, buf, len);
randPoolAddPos += len;
randPoolGetPos = sizeof(randPool); /* Force stir on get */
}
}
/*
* Withdraw some bits from the pool. Regardless of the distribution of the
* input bits, the bits returned are uniformly distributed, although they
* cannot, of course, contain more Shannon entropy than the input bits.
*/
void
randPoolGetBytes(byte *buf, unsigned len)
{
unsigned t;
while (len > (t = sizeof(randPool) - randPoolGetPos)) {
memcpy(buf, (byte *)randPool+randPoolGetPos, t);
buf += t;
len -= t;
randPoolStir();
}
if (len) {
memcpy(buf, (byte *)randPool+randPoolGetPos, len);
randPoolGetPos += len;
}
}
byte
randPoolGetByte(void)
{
if (randPoolGetPos == sizeof(randPool))
randPoolStir();
return (((byte *)randPool)[randPoolGetPos++]);
}